package pl.easyshop.core.services.category;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import pl.easyshop.core.model.CategoryModel;
import pl.easyshop.core.services.AbstractBaseService;

/**
 * Default implementation of interface {@link CategoryService}.
 * 
 * @author Pawel Witkowski
 */
@Service("categoryService")
public class CategoryServiceImpl extends AbstractBaseService implements CategoryService {

	/** Logger. */
	private final static Logger LOG = Logger.getLogger(CategoryServiceImpl.class);
	
	@Override
	@Transactional
	public Long createCategory(CategoryData category) {
		LOG.info("Invokde createCategory");
		LOG.debug("Category data: " + category);
		CategoryModel model = getDozerMapper().map(category, CategoryModel.class);
		LOG.debug("New category data: " + model);
		if(category.getParentCategoryId() != null) {
			CategoryModel parentCategory = getDAORegistry().getCategoryDAO().load(category.getParentCategoryId());	
			parentCategory.addSubCategory(model);
			model.setParentCategory(parentCategory);
		} 
		
		return getDAORegistry().getCategoryDAO().save(model);
	}
	
	@Override
	@Transactional(readOnly=true)
	public CategoryData getCategory(Long categoryId) {
		LOG.info("Invokde createCategory");
		LOG.debug("Try load category with id: " + categoryId);
		CategoryModel model = getDAORegistry().getCategoryDAO().load(categoryId);
		CategoryData categoryData = null;
		if(model != null){
			categoryData = getDozerMapper().map(model, CategoryData.class);
			LOG.debug("Loaded category data: " + categoryData);
		}
		return categoryData;
	}
	
	@Override
	@Transactional
	public void updateCategory(CategoryData category) {
		LOG.info("Invoke updateCategory");
		CategoryModel model = getDozerMapper().map(category, CategoryModel.class);
		getDAORegistry().getCategoryDAO().update(model);
	}
	
	@Override
	@Transactional(readOnly=true)
	public List<CategoryData> getMainCategories() {
		LOG.info("Invoke getMainCategories");
		DetachedCriteria criteria = DetachedCriteria.forClass(CategoryModel.class);
		criteria.add(Restrictions.isNull("parentCategory"));
		List<CategoryModel> modelList = getDAORegistry().getCategoryDAO().find(criteria);
		List<CategoryData> resultList = new ArrayList<CategoryData>();
		if(!modelList.isEmpty()) {
			LOG.info("Found main categories: " + modelList.size());
			CategoryData data = null;
			for (CategoryModel categoryModel : modelList) {
				data = getDozerMapper().map(categoryModel, CategoryData.class);
				resultList.add(data);
				LOG.debug("Main category: " + data);
			}
		}
		return resultList;
	}

	@Override
	@Transactional(readOnly=true)
	public List<CategoryData> getSubCategories(Long parentCategoryId) {
		LOG.info("Invoke getSubCategories");
		DetachedCriteria criteria = DetachedCriteria.forClass(CategoryModel.class);
		criteria.createAlias("parentCategory", "parent");
		criteria.add(Restrictions.eq("parent.id", parentCategoryId));
		List<CategoryModel> modelList = getDAORegistry().getCategoryDAO().find(criteria);
		List<CategoryData> resultList = new ArrayList<CategoryData>();
		if(!modelList.isEmpty()) {
			LOG.info("Found sub categories: " + modelList.size());
			CategoryData data = null;
			for (CategoryModel categoryModel : modelList) {
				data = getDozerMapper().map(categoryModel, CategoryData.class);
				resultList.add(data);
				LOG.debug("Sub category: " + data);
			}
		}
		return resultList;
	}

	@Override
	@Transactional
	public void removeCategory(Long categoryId) {
		LOG.info("Invoke removeCategory");
		getDAORegistry().getCategoryDAO().delete(categoryId);
	}

}
